from django.db import transaction
from rest_framework import serializers
from apps.goods.models import SKU, GoodsCategory, SPU, SpecificationOption, SPUSpecification, SKUSpecification


class SKUSpecificationSerialzier(serializers.ModelSerializer):
    """SKU规格表序列化器"""
    spec_id = serializers.IntegerField()
    option_id = serializers.IntegerField()

    class Meta:
        model = SKUSpecification
        fields = ("spec_id", 'option_id')


class SKUSerializer(serializers.ModelSerializer):
    """sku管理的序列化器"""

    # 因为前端需要数据spu_id和category_id数据，而SKU模型中并没有，所以我们要自己定义
    spu_id = serializers.IntegerField()
    category_id = serializers.IntegerField()
    # 因为抓取前端包时候，发现category和spu是个必传字段，所以我们重写
    spu = serializers.StringRelatedField(read_only=True)
    category = serializers.StringRelatedField(read_only=True)

    # 定义specs字段来接收规格信息
    # 规格信息是一个列表 many=Tue
    # 规格信息 spec_id 和 option_id 和 SKUSpecification 对应
    # 于是我们定义 SKUSpecificationSerialzier
    # 期望 SKUSpecificationSerialzier 序列化器帮助我们实现 反序列化操作
    specs = SKUSpecificationSerialzier(many=True)

    class Meta:
        model = SKU
        fields = "__all__"
    # 嵌套串行器是只读的。如果要支持对嵌套序列化器字段的写操作，则需要创建create()和/或update()方法，以明确指定应如何保存子关系。
    # 因为我们是增加 所以要重写create方法
    def create(self, validated_data):
        # 获取规格信息,并从validated_data数据中,删除规格信息数据
        # 因为是嵌套所以先筛选出规格信息
        specs_data = validated_data.pop("specs")

        # 添加事务
        with transaction.atomic():
            # 开启事务
            savepoint = transaction.savepoint()

        # 保存sku
        sku = SKU.objects.create(**validated_data)
        # 对规格信息进行遍历,来保存商品规格信息
        for spec_data in specs_data:
            SKUSpecification.objects.create(sku=sku,**spec_data)

        # 清除保存点
        transaction.savepoint_commit(savepoint)
        # 返回sku
        return sku

    def update(self, instance, validated_data):
        # 更新SKU表数据
        # 获取规格信息,并从validated_data数据中,删除规格信息数据
        specs_data = validated_data.pop("specs")

        # 调用父类 ，去实现没有问题的数据更新
        super().update(instance,validated_data)

        # 对规格信息进行遍历,来保存商品规格信息
        for spec_data in specs_data:
            # item {spec_id: "4", option_id: 8}
            SKUSpecification.objects.filter(sku=instance,spec_id=spec_data.get("spec_id")).\
                update(option_id=spec_data.get("option_id"))
        # 返回数据
        return instance

class SKUCategorieSerializer(serializers.ModelSerializer):
    """sku三级分类序列化器"""

    class Meta:
        model = GoodsCategory
        fields = "__all__"


class GoodsSimpleSerializer(serializers.ModelSerializer):
    """获取SPU表名称信息"""

    class Meta:
        model = SPU
        fields = "__all__"


class GoodsOptineSerializer(serializers.ModelSerializer):
    """规格选项序列化器"""

    class Meta:
        model = SpecificationOption
        fields = ("id", "value")


class GoodsSpecSerialzier(serializers.ModelSerializer):
    """因为前端传递的数据是这样2个字段"""

    # 之前的数据表里 没有我们所需要的字段 所以要自己定义
    spu = serializers.StringRelatedField()
    spu_id = serializers.IntegerField()

    # 关联序列化返回 规格选项信息
    # 使用规格选项序列化器
    options = GoodsOptineSerializer(many=True)

    # SPUSpecification中的外键spu关联了SPU商品表
    class Meta:
        model = SPUSpecification
        fields = "__all__"
